package com.blank.black.service.impl;

import com.blank.black.common.BlankUtils;
import com.blank.black.entity.bo.example.CommonExample;
import com.blank.black.entity.pojo.BlankConfig;
import com.blank.black.entity.pojo.ConfigCol;
import com.blank.black.entity.pojo.ConfigCriteria;
import com.blank.black.entity.pojo.ConfigJoin;
import com.blank.black.enums.BooleanEnum;
import com.blank.black.enums.ColTypeEnum;
import com.blank.black.enums.ConfigTypeEnum;
import com.blank.black.mapper.*;
import com.blank.black.service.IBlankConfigService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * example列配置表 服务实现类
 * </p>
 *
 * @author htr
 * @since 2024-02-23
 */
@Service
public class BlankConfigServiceImpl implements IBlankConfigService {

    @Resource
    private BlankConfigMapper blankConfigMapper;
    @Resource
    private ConfigJoinMapper configJoinMapper;
    @Resource
    private ConfigColMapper configColMapper;
    @Resource
    private ConfigCriteriaMapper configCriteriaMapper;
    @Resource
    private CommonMapper commonMapper;

    @Override
    public Map<String, Object> listByConfigName(String preUrl, String configName, Map<String, Object> param) throws Exception {
        // 查询所有example配置项
        Map<String, Object> resultmap = new HashMap<>();
        BlankConfig exampleConfig = this.selectByConfigName(preUrl,configName);
        if (Objects.isNull(exampleConfig)) {
            return resultmap;
        }
        return this.listByConfigExampleConfig(exampleConfig, param);
    }

    @Override
    public Map<String, Object> listByConfigId(Long id, Map<String, Object> param) throws Exception {
        // 查询所有example配置项
        Map<String, Object> resultmap = new HashMap<>();
        BlankConfig exampleConfig = this.selectById(id);
        if (Objects.isNull(exampleConfig)) {
            return resultmap;
        }
        return this.listByConfigExampleConfig(exampleConfig, param);
    }

    private Map<String, Object> listByConfigExampleConfig(BlankConfig exampleConfig, Map<String, Object> param) throws Exception {
        // 查询所有example配置项
        Map<String, Object> resultmap = new HashMap<>();
        if (Objects.isNull(exampleConfig)) {
            return resultmap;
        }
        CommonExample example = BlankUtils.config2CommonExample(exampleConfig, param);
        // 查询
        if (BooleanEnum.TRUE.getCode().equals(exampleConfig.getPageFlag())) {
            long num = commonMapper.countByExample(example);
            Integer pageSize = Objects.isNull(param.get("pageSize")) ? exampleConfig.getPageSize() : BlankUtils.getIngeter(param, "pageSize");
            Integer pageNum = Objects.isNull(param.get("pageNum")) ? 1 : BlankUtils.getIngeter(param, "pageNum");
            resultmap.put("total", num);
            resultmap.put("pageSize", pageSize);
            resultmap.put("pageNum", pageNum);
            resultmap.put("pageTotal", new BigDecimal(num).divide(new BigDecimal(pageSize), 0, RoundingMode.UP));

        }
        List<Map<String, Object>> mapList = this.execConfig(exampleConfig, example, param);
        if(ConfigTypeEnum.SELECT.getCode().equals(exampleConfig.getType())) {
            resultmap.put("list", mapList);
            //顶层数据聚合
            this.parseGroupCol(resultmap, exampleConfig, mapList);
        }else if(ConfigTypeEnum.SELECT_ONE.getCode().equals(exampleConfig.getType())) {
            return mapList.get(0);
        }

        return resultmap;
    }

    @Override
    public Integer updateByConfigId(Long id, Map<String, Object> param) throws Exception {
        // 查询所有example配置项
        Map<String, Object> resultmap = new HashMap<>();
        BlankConfig exampleConfig = this.selectById(id);
        if (Objects.isNull(exampleConfig)) {
            return BooleanEnum.FALSE.getCode();
        }
        CommonExample example = BlankUtils.config2CommonExample(exampleConfig, param);
        // 查询
        return commonMapper.updateByExampleSelective(example);
    }

    @Override
    public Integer deleteByConfigId(Long id, Map<String, Object> param) throws Exception {
        Map<String, Object> resultmap = new HashMap<>();
        BlankConfig exampleConfig = this.selectById(id);
        if (Objects.isNull(exampleConfig)) {
            return BooleanEnum.FALSE.getCode();
        }
        CommonExample example = BlankUtils.config2CommonExample(exampleConfig, param);
        // 查询
        return commonMapper.deleteByExample(example);
    }

    @Override
    public Integer insertByConfigId(Long id, Map<String, Object> param) throws Exception {
        Map<String, Object> resultmap = new HashMap<>();
        BlankConfig exampleConfig = this.selectById(id);
        if (Objects.isNull(exampleConfig)) {
            return BooleanEnum.FALSE.getCode();
        }
        CommonExample example = BlankUtils.config2CommonExample(exampleConfig, param);
        // 查询
        return commonMapper.insertByExampleSelective(example);
    }



    private List<Map<String, Object>> execConfig(BlankConfig exampleConfig, CommonExample example, Map<String, Object> param) throws Exception {

        List<Map<String, Object>> mapList = commonMapper.selectByExample(example);

        // 递归子查询
        if (!Objects.isNull(exampleConfig.getCountChild()) && exampleConfig.getCountChild() > 0) {
            for (BlankConfig config : exampleConfig.getChildList()) {
                Map<String, Object> childreParam = new HashMap<>();
                String[] pcolNameList = config.getPcolName().split(",");
                for (String pcol : pcolNameList) {
                    childreParam.put(pcol, mapList.stream().map(item -> item.get(pcol)).collect(Collectors.toList()));
                }
                CommonExample childExample = BlankUtils.config2CommonExample(config, childreParam);
                List<Map<String, Object>> childrenMap = this.execConfig(config, childExample, childreParam);

                this.parseChildGroupCol(mapList, config, pcolNameList, childrenMap);
            }
        }
        return mapList;

    }

    /**
     * 顶层聚合数据
     *
     * @param map
     * @param config
     * @param collect
     */
    private void parseGroupCol(Map<String, Object> map, BlankConfig config, List<Map<String, Object>> collect) {
        List<ConfigCol> groupColList = config.getColList().stream().filter(item -> !ColTypeEnum.VALUE.getCode().equals(item.getColType())).collect(Collectors.toList());
        for (ConfigCol configCol : groupColList) {
            Map<String, Object> colMap = new HashMap<>();
            // 计算，并将值放入父级map
            if (ColTypeEnum.SUM.getCode().equals(configCol.getColType())) {
                BigDecimal decimal = BigDecimal.ZERO;
                for (Map<String, Object> itemMap : collect) {
                    if (this.isColOfChildrenNUll(itemMap, configCol)) {continue;}
                    decimal = decimal.add(new BigDecimal(itemMap.get(configCol.getColName()).toString()));
                }
                map.put(configCol.getColAlias(), decimal.toString());
            }

            if (ColTypeEnum.AVG.getCode().equals(configCol.getColType())) {
                BigDecimal decimal = BigDecimal.ZERO;
                for (Map<String, Object> itemMap : collect) {
                    if (this.isColOfChildrenNUll(itemMap, configCol)) {continue;}
                    decimal = decimal.add(new BigDecimal(itemMap.get(configCol.getColName()).toString()));
                }
                map.put(configCol.getColAlias(), decimal.divide(new BigDecimal(collect.size()), 2, RoundingMode.HALF_UP));
            }
            if (ColTypeEnum.MAX.getCode().equals(configCol.getColType())) {
                BigDecimal decimal = null;
                Boolean firstFlag = true;
                for (Map<String, Object> itemMap : collect) {
                    if (this.isColOfChildrenNUll(itemMap, configCol)) {continue;}
                    BigDecimal itemDecimal = new BigDecimal(itemMap.get(configCol.getColName()).toString());
                    if (firstFlag) {
                        decimal = new BigDecimal(itemMap.get(configCol.getColName()).toString());
                        firstFlag = false;
                    }
                    if (decimal.compareTo(itemDecimal) < 0) {
                        decimal = itemDecimal;
                    }
                }
                map.put(configCol.getColAlias(), decimal);
            }
            if (ColTypeEnum.MIN.getCode().equals(configCol.getColType())) {
                BigDecimal decimal = null;
                Boolean firstFlag = true;
                for (Map<String, Object> itemMap : collect) {
                    if (this.isColOfChildrenNUll(itemMap, configCol)) {continue;}
                    BigDecimal itemDecimal = new BigDecimal(itemMap.get(configCol.getColName()).toString());
                    if (firstFlag) {
                        decimal = new BigDecimal(itemMap.get(configCol.getColName()).toString());
                        firstFlag = false;
                    }
                    if (decimal.compareTo(itemDecimal) > 0) {
                        decimal = itemDecimal;
                    }
                }
                map.put(configCol.getColAlias(), decimal);
            }
        }

    }

    private boolean isColOfChildrenNUll(Map<String, Object> itemMap, ConfigCol configCol) {
        if (Objects.isNull(itemMap.get(configCol.getColName()))) {
            return true;
        }
        return false;
    }


    /**
     * 子级聚合数据
     *
     * @param mapList
     * @param config
     * @param pcolNameList
     * @param childrenMap
     */
    private void parseChildGroupCol(List<Map<String, Object>> mapList, BlankConfig config, String[] pcolNameList, List<Map<String, Object>> childrenMap) {
        Map<String, List<Map<String, Object>>> childCollect = childrenMap.stream().collect(Collectors.groupingBy(item -> {
            StringBuilder sb = new StringBuilder();
            for (String s : pcolNameList) {
                sb.append(item.get(s));
                sb.append("@{-}");
            }
            return sb.toString();
        }));
        List<ConfigCol> groupColList = config.getColList().stream().filter(item -> !ColTypeEnum.VALUE.getCode().equals(item.getColType())).collect(Collectors.toList());
        for (ConfigCol configCol : groupColList) {
            // 计算，并将值放入父级map
            for (Map<String, Object> pItem : mapList) {
                StringBuilder sb = new StringBuilder();
                for (String s : pcolNameList) {
                    sb.append(pItem.get(s));
                    sb.append("@{-}");
                }
                String key = sb.toString();
                if (Objects.isNull(childCollect.get(key))) {
                    childCollect.put(key, new ArrayList<>());
                }
                if (ColTypeEnum.SUM.getCode().equals(configCol.getColType())) {
                    BigDecimal decimal = BigDecimal.ZERO;
                    for (Map<String, Object> itemMap : childCollect.get(key)) {
                        if (this.isColOfChildrenNUll(itemMap, configCol)) {continue;}
                        decimal = decimal.add(new BigDecimal(itemMap.get(configCol.getColName()).toString()));
                    }
                    pItem.put(configCol.getColAlias(), decimal);

                }
                if (ColTypeEnum.AVG.getCode().equals(configCol.getColType())) {
                    BigDecimal decimal = BigDecimal.ZERO;
                    for (Map<String, Object> itemMap : childCollect.get(key)) {
                        if (this.isColOfChildrenNUll(itemMap, configCol)) {continue;}
                        decimal = decimal.add(new BigDecimal(itemMap.get(configCol.getColName()).toString()));
                    }
                    pItem.put(configCol.getColAlias(), decimal.divide(new BigDecimal(childCollect.get(key).size()), 2, RoundingMode.HALF_UP));

                }
                if (ColTypeEnum.MAX.getCode().equals(configCol.getColType())) {
                    BigDecimal decimal = null;
                    Boolean firstFlag = true;
                    for (Map<String, Object> itemMap : childCollect.get(key)) {
                        if (this.isColOfChildrenNUll(itemMap, configCol)) {continue;}
                        BigDecimal itemDecimal = new BigDecimal(itemMap.get(configCol.getColName()).toString());
                        if (firstFlag) {
                            decimal = new BigDecimal(itemMap.get(configCol.getColName()).toString());
                            firstFlag = false;
                        }
                        if (decimal.compareTo(itemDecimal) < 0) {
                            decimal = itemDecimal;
                        }
                    }
                    pItem.put(configCol.getColAlias(), decimal);
                }
                if (ColTypeEnum.MIN.getCode().equals(configCol.getColType())) {
                    BigDecimal decimal = null;
                    Boolean firstFlag = true;
                    for (Map<String, Object> itemMap : childCollect.get(key)) {
                        if (this.isColOfChildrenNUll(itemMap, configCol)) {continue;}
                        BigDecimal itemDecimal = new BigDecimal(itemMap.get(configCol.getColName()).toString());
                        if (firstFlag) {
                            decimal = new BigDecimal(itemMap.get(configCol.getColName()).toString());
                            firstFlag = false;
                        }
                        if (decimal.compareTo(itemDecimal) > 0) {
                            decimal = itemDecimal;
                        }
                    }
                    pItem.put(configCol.getColAlias(), decimal);

                }
                if (ColTypeEnum.CHILD_LIST.getCode().equals(configCol.getColType())) {
                    pItem.put(configCol.getColAlias(), childCollect.get(key));

                }
            }
        }
    }

    /**
     * 查询配置
     *
     * @param id
     * @return
     */
    public BlankConfig selectById(Long id) throws Exception {
        if (Objects.isNull(id)) {
            return null;
        }
        BlankConfig exampleConfig = blankConfigMapper.selectById(id);
        return this.genExampleConfig(id, exampleConfig);
    }

    private BlankConfig selectByConfigName(String preName, String configName) throws Exception {
        if (Objects.isNull(configName)||configName.length() ==0 ) {
            return null;
        }
        List<BlankConfig> exampleConfigList = blankConfigMapper.selectByConfigName(preName,configName);
        if (Objects.isNull(exampleConfigList)||exampleConfigList.size() ==0 ) {
            return null;
        }
        BlankConfig exampleConfig = exampleConfigList.get(0);
        if (Objects.nonNull(exampleConfig)) {
            exampleConfig.setCountChild(blankConfigMapper.countChild(exampleConfig.getId()));
        }
        return this.genExampleConfig(exampleConfig.getId(), exampleConfig);
    }

    private BlankConfig genExampleConfig(Long id, BlankConfig exampleConfig) throws Exception {
        if (Objects.isNull(exampleConfig)) {
            return null;
        }
        if (!exampleConfig.getPid().equals(Long.valueOf(0))) {
            throw new Exception("该配置不为最上级配置");
        }
        List<BlankConfig> childList = new ArrayList<>();
        List<Long> idList = new ArrayList<>();
        idList.add(exampleConfig.getId());
        if (exampleConfig.getCountChild().compareTo(Integer.valueOf(0)) > 0) {
            childList = blankConfigMapper.listChiildrenById(id);
            idList.addAll(childList.stream().map(item -> item.getId()).collect(Collectors.toList()));
        }
        List<ConfigJoin> exampleJoinList = configJoinMapper.listByConfigIdList(idList);
        List<ConfigCol> colList = configColMapper.listByConfigIdList(idList);
        List<ConfigCriteria> criteriaList = configCriteriaMapper.listByConfigIdList(idList);
        // 组装数据
        exampleConfig = this.assemblyDate(exampleConfig, childList, colList, exampleJoinList, criteriaList);
        return exampleConfig;
    }


    /**
     * 组装example_config数据
     *
     * @param exampleConfig
     * @param childList
     * @param colList
     * @param exampleJoinList
     * @param criteriaList
     * @return
     */
    private BlankConfig assemblyDate(BlankConfig exampleConfig, List<BlankConfig> childList, List<ConfigCol> colList,
                                     List<ConfigJoin> exampleJoinList, List<ConfigCriteria> criteriaList) {
        if (Objects.isNull(exampleConfig) || Objects.isNull(exampleConfig.getId())) {
            return null;
        }
        exampleConfig.setColList(colList.stream().filter(item -> exampleConfig.getId().equals(item.getConfigId())).collect(Collectors.toList()));
        exampleConfig.setJoinList(exampleJoinList.stream().filter(item -> exampleConfig.getId().equals(item.getConfigId())).collect(Collectors.toList()));
        exampleConfig.setCriteriaList(criteriaList.stream().filter(item -> exampleConfig.getId().equals(item.getConfigId())).collect(Collectors.toList()));
        List<BlankConfig> currentChildren = childList.stream().filter(item -> exampleConfig.getId().equals(item.getPid())).collect(Collectors.toList());
        if (!Objects.isNull(currentChildren) && currentChildren.size() > 0) {
            for (BlankConfig item : currentChildren) {
                item = this.assemblyDate(item, childList, colList, exampleJoinList, criteriaList);
            }
            exampleConfig.setChildList(currentChildren);
        }
        return exampleConfig;
    }
}
